#include "App.h"

#include "Nidhoggr.h"

#if defined(__APPLE__) || defined(MACOSX)
	#include <OpenGL/gl.h>
	#include <OpenGL/glu.h>
	#include <OpenGL/OpenGL.h>
	#include <GLUT/glut.h>
#endif
#if defined(_WIN32)
	#include <GL/gl.h>
	#include <GL/glu.h>
	#include <GL/glut.h>
#endif

#include <iostream>

#include "Entity.h"
#include "Widget.h"
#include "Defines.h"
#include "Printer.h"
#include "Compositor.h"



namespace Y{

//Nidhoggr * Nidhoggr::app_ptr = NULL;
		

Nidhoggr::Nidhoggr():
	openGLInitialized		(false),
	lastMouse				(0.0,0.0),
	counter					(0),
	pixelWidth				(1),
	pixelHeight				(1),
	openGLWidth				(1),
	openGLHeight			(1),
	focusedWidget			(NULL),
	lastClickedWidget		(NULL),
	mousedOverWidget		(NULL),
	draggingWidget			(NULL),
	texturesInitialized	(false),
	widgetsInitialized	(false)
{
}

void Nidhoggr::initialize ( std::vector< OString >& argv ){

	executablePath = argv[0];
	#if defined(__APPLE__) || defined(MACOSX)
		resourcePath = executablePath.rcullOnFrom("build") + "Resources/";
		std::cout << "\n" << resourcePath;
		
		OString::OS = MAC;
//		std::fstream testStream( resourcePath + "Widget/yButton/button_32.png", std::ios::in );
//		if ( ! testStream ){
//			resourcePath = executablePath.rcullOnFrom("MacOS") + "Resources/Resources/";
//			pvar( resourcePath );
//		}
//		else{ testStream.close(); }
	#endif
	#if defined(_WIN32)
		resourcePath = executablePath;
		std::cout << "\n" << (resourcePath);
		
		OString::OS = WINDOWS;
	#endif
	
	initTextures();
	initWidgets();
	initCompositor();
}

void Nidhoggr::initTextures (){
	textureStorage["empty"] = Texture();
	textureStorage_id_to_texture[0] = & textureStorage["empty"];
	textureStorage_id_to_name[0] = "empty";
	emptyTexture = & textureStorage["empty"];
	
	std::vector < Texture * > texVect;
	
	texVect.push_back( loadTextureForTextureBlock("d button body",resourcePath + "Widget/Button/button_32.png") );
	texVect.push_back( loadTextureForTextureBlock("d button end",resourcePath + "Widget/Button/buttonEnd_32.png") );
	texVect.push_back( loadTextureForTextureBlock("d button end 2",resourcePath + "Widget/Button/buttonEnd2_32.png") );
	
	texVect.push_back( loadTextureForTextureBlock("d button down bod",resourcePath + "Widget/Button/buttondown_32.png") );
	texVect.push_back( loadTextureForTextureBlock("d button down end",resourcePath + "Widget/Button/buttondownEnd_32.png") );
	texVect.push_back( loadTextureForTextureBlock("d button down end 2",resourcePath + "Widget/Button/buttondownEnd2_32.png") );
	
	texVect.push_back( loadTextureForTextureBlock("d menu cell bod",resourcePath + "Widget/Menu/cell.png") );
	texVect.push_back( loadTextureForTextureBlock("d menu cell end",resourcePath + "Widget/Menu/cellend.png") );
	texVect.push_back( loadTextureForTextureBlock("d menu cell end 2",resourcePath + "Widget/Menu/cellend2.png") );
	
	texVect.push_back( loadTextureForTextureBlock("d menu bod",resourcePath + "Widget/Menu/menu.png") );
	texVect.push_back( loadTextureForTextureBlock("d menu end",resourcePath + "Widget/Menu/menuend.png") );
	texVect.push_back( loadTextureForTextureBlock("d menu end 2",resourcePath + "Widget/Menu/menuend2.png") );
	
	texVect.push_back( loadTextureForTextureBlock("d window bar bod",resourcePath + "Widget/WindowBar/barbody.png") );
	texVect.push_back( loadTextureForTextureBlock("d window bar end",resourcePath + "Widget/WindowBar/barend.png") );
	texVect.push_back( loadTextureForTextureBlock("d window bar end 2",resourcePath + "Widget/WindowBar/barend2.png") );
	
	texVect.push_back( loadTextureForTextureBlock("d close button",resourcePath + "Widget/WindowBar/closeBox.png") );
	texVect.push_back( loadTextureForTextureBlock("d minimize button",resourcePath + "Widget/WindowBar/minBox.png") );
	texVect.push_back( loadTextureForTextureBlock("d maximize button",resourcePath + "Widget/WindowBar/maxBox.png") );
	
	texVect.push_back( loadTextureForTextureBlock("d scroll bar bod",resourcePath + "Widget/ScrollBar/scrollbarbody.png") );
	texVect.push_back( loadTextureForTextureBlock("d scroll bar end",resourcePath + "Widget/ScrollBar/scrollbarend.png") );
	texVect.push_back( loadTextureForTextureBlock("d scroll bar end 2",resourcePath + "Widget/ScrollBar/scrollbarend2.png") );
	
	texVect.push_back( loadTextureForTextureBlock("d scroll arrow",resourcePath + "Widget/ScrollBar/arrow.png") );
	
	texVect.push_back( loadTextureForTextureBlock("skull pirate",resourcePath + "Textures/skullPirate.png") );
	texVect.push_back( loadTextureForTextureBlock("airy girl",resourcePath + "Textures/airyGirl.png") );
	texVect.push_back( loadTextureForTextureBlock("fairyfly",resourcePath + "Textures/fairyfly.png") );
	
	texVect.push_back( loadTextureForTextureBlock("zero",resourcePath + "Textures/zero.png") );
	
	fonts["sam font"] = Font(resourcePath + "Font/sfont");
		currentFont = & fonts["sam font"];
		
	texVect.push_back( currentFont->fontTexture );
	
//	zeroTexture = new OTexture(256,256);
//	for ( int i = 0; i < 4; ++i ){ for ( int j = 0; j < 4; ++j ){ for ( int q = 0; q < 4; ++q ){ zeroTexture->acc(i,j,q) = 100; } zeroTexture->acc(i,j,3) = 255; } }
//	texvect.push_back(zeroTexture);
	
	textureBlockStorage["ui texture block"] = new TextureBlock(2048,2048,16);
	bool bel = textureBlockStorage["ui texture block"]->addTextures(texVect);
	if ( ! bel ){ Printer() << "bel is false, check the ui texture block loading stuff"; }
	
	texturesInitialized = true;
}

void Nidhoggr::initWidgets (){
	Widget * w = new Widget( NULL );
	w->configure(
		C( position, 0.0f,0.0f,0.0f ),
		C( dimensions, 4.0f,4.0f ),
		C( color, 1.0f, 0.0f, 0.0f, 1.0f ),
		C( texture, getTexture("fairyfly") )
	);
	
	
	Widget * child = new Widget ( w );
	child->configure(
		C( position, 3.0f,0.5f,0.0f ),
		C( dimensions, 2.0f,2.0f ),
		C( color, 0.0,0.0,0.0,0.7)
	);
	
	widgetsInitialized = true;
}

void Nidhoggr::initCompositor (){
	compositor = new Compositor();
	compositor->state.in_clearColor(1,1,1,1);
	compositor->state.in_nullTexture = (getTexture("zero"));
	compositor->state.in_startPosition(0,0,0);
}

//Entity functions
void Nidhoggr::firstRites ( Entity *entity ){
	entities.insert( entity );
	entityIDmap[entity->ID] = entity;
}

void Nidhoggr::lastRites ( Entity *entity ){

	for ( int i = 0; i < entity->children.size(); ++i ){
		for ( int j = 0; j < releaseQ.size(); ++j ){	
			if ( releaseQ[j] == entity->children[i] ){
				releaseQ.erase( releaseQ.begin() + j );
				--j;
			}
		}
		delete entity->children[i];
	}
	
	entities.erase(entity);
	entityIDmap.erase(entityIDmap.find(entity->ID));
}

void Nidhoggr::lastRites ( Widget *widget ){
	
	if ( focusedWidget == widget ){ focusedWidget = NULL; }
	if ( lastClickedWidget == widget ){ lastClickedWidget = NULL; }
	if ( mousedOverWidget == widget ){ mousedOverWidget = NULL; }
	if ( draggingWidget == widget ){ draggingWidget = NULL; }
}


void Nidhoggr::firstRites (Widget *w){
	widgets.insert(w);
}

void Nidhoggr::changeFocusedWidget( Widget* w ){
	if ( w == NULL ){ focusedWidget = NULL; }
	else{
	
		Widget *tmp = w;
		while ( ! tmp->acceptsEvent( FOCUS ) ){
			if ( tmp == NULL ){ break; }
			tmp = (Widget*)tmp->parent();
		}
		
		focusedWidget = tmp;
		
	}
}


void Nidhoggr::changeDraggingWidget( Widget* w ){
	if ( w == NULL ){ draggingWidget = NULL; }
	else{
	
		Widget *tmp = w;
		while ( ! tmp->acceptsEvent( MOUSE_DRAG ) ){
			tmp = (Widget*)tmp->parent();
			if ( tmp == NULL ){ break; }
		}
		
		draggingWidget = tmp;
		
	}
}


//Event Functions
void Nidhoggr::mousePress(int x, int y){
	
	GLuint nomen = selection(x,y,0);
	changeFocusedWidget( (Widget*)entityIDmap[nomen] );
	changeDraggingWidget( (Widget*)entityIDmap[nomen] );
	lastClickedWidget = (Widget*) entityIDmap[nomen];
	
	if ( focusedWidget != NULL ) focusedWidget->eventSubsystem( x,y,MOUSE_PRESS );
	else{
		for ( iteratorLoop2( defaultWidgets, it ) ){
			it->second->eventSubsystem( x,y,MOUSE_PRESS );
		}
	}
}
void Nidhoggr::mouseRelease(int x, int y){
	
	if ( lastClickedWidget != NULL ) lastClickedWidget->eventSubsystem( x,y,MOUSE_RELEASE );
	else{
		for ( iteratorLoop2( defaultWidgets, it ) ){
			it->second->eventSubsystem( x,y,MOUSE_RELEASE );
		}
	}
}
void Nidhoggr::mouseMove(int x, int y){
	lastMouse((float)x,(float)y);
	
	GLuint nomen = selection(x,y,0);
	Widget *w = (Widget *) entityIDmap[nomen];
	if ( w != mousedOverWidget ){
		if ( mousedOverWidget != NULL ){
			mousedOverWidget->eventSubsystem( EXIT_EVENT ); 
		}
		if ( w != NULL ){
			w->eventSubsystem( ENTER_EVENT );
		}
		mousedOverWidget = w;
	}
	
	if ( focusedWidget != NULL ) focusedWidget->eventSubsystem( x,y,MOUSE_MOVE );
	else{
		for ( iteratorLoop2( defaultWidgets, it ) ){
			it->second->eventSubsystem( x,y,MOUSE_MOVE );
		}
	}
}
void Nidhoggr::mouseDrag(int x, int y){
	
	if ( draggingWidget != NULL ) draggingWidget->eventSubsystem( lastMouse.x() - (float)x,lastMouse.y() - (float)y,MOUSE_DRAG );
	else{
		for ( iteratorLoop2( defaultWidgets, it ) ){
			it->second->eventSubsystem( lastMouse.x() - (float)x,lastMouse.y() - (float)y,MOUSE_DRAG );
		}
	}
	
	lastMouse((float)x,(float)y);
}

	GLuint Nidhoggr::selection(int x, int y, int mode, void (Nidhoggr::*p) ()){
		if (p == NULL){p = & Nidhoggr::selectionPaintGL;}
		GLuint buffer[512];
		
		GLint hits;
		GLint viewport[4] ;

		glGetIntegerv(GL_VIEWPORT, viewport);
		glSelectBuffer(512, buffer);
		(void) glRenderMode(GL_SELECT);
		glInitNames();
		glPushName(0);
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glLoadIdentity();
		
		gluPickMatrix(x,(GLdouble) viewport[3] - y, 1.0f, 1.0f, viewport);
		if(viewport[3] - viewport[1] != 0){
		gluPerspective(45.0f,(GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]),0.1f,300.0f);}
		glMatrixMode(GL_MODELVIEW);
		
		//================================
			selectionPaintGL();
		//================================
		
		glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		hits = glRenderMode(GL_RENDER);
		if (hits > 0){
			int choose;
			if (mode == 0){
				choose = 0;						
				
				for (int i = hits - 1; i >= 0; --i){
					if (buffer[i * 4 + 3] != 0){
						choose = buffer[i * 4 + 3];			//<-------Lastmost drawn
						break;
					}
				}
			}

			else if (mode == 1){
				choose = buffer[3];
				int depth = buffer[1];
				for(unsigned int i = 1; i < hits; i++){
					if(buffer[i*4+1] < GLuint(depth)){		//<-------Topmost Depth
						choose = buffer[i*4+3];
						depth = buffer[i*4+1];
					}
				}
			}
			return choose;
		}
		return 0;
	}
	
void Nidhoggr::scrollWheel(float dx,float dy,float dz){
	
	if ( focusedWidget != NULL ) focusedWidget->eventSubsystem( dx,dy,dz,MOUSE_SCROLL );
	else{
		for ( iteratorLoop2( defaultWidgets, it ) ){
			it->second->eventSubsystem( dx,dy,dz,MOUSE_SCROLL );
		}
	}
}
void Nidhoggr::keyPress(unsigned char c, int mod){
	keyModifiers = mod;
	
	if ( focusedWidget != NULL ) focusedWidget->eventSubsystem( c,mod,KEY_PRESS );
	else{
		for ( iteratorLoop2( defaultWidgets, it ) ){
			it->second->eventSubsystem( c,mod,KEY_PRESS );
		}
	}
}
void Nidhoggr::keyRelease(unsigned char c, int mod){
	keyModifiers = mod;
	
	if ( focusedWidget != NULL ) focusedWidget->eventSubsystem( c,mod,KEY_RELEASE );
	else{
		for ( iteratorLoop2( defaultWidgets, it ) ){
			it->second->eventSubsystem( c,mod,KEY_RELEASE );
		}
	}
}

int	 Nidhoggr::getKeyModifiers() const{
	return keyModifiers;
}

void Nidhoggr::subTimer(float x){
	
	while ( ! releaseQ.empty() ){
		delete ( releaseQ.front() );
		releaseQ.pop_front();
	}
	
	counter += x;
	for ( iteratorLoop2( entities,it ) ){
		if ( (*it)->parent() == NULL ){
			(*it)->timerSubsystem(x);
		}
	}
	
	timer(x);
}


void Nidhoggr::timer(float){
	if ( widgetsInitialized && texturesInitialized ){
		compositor->composite();
	}
}

void Nidhoggr::paintGL (){

	if ( counter == 0 ){ 
		initialize( args );
	}
	
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	glLoadIdentity();
	
	glTranslatef(0,0,-10);
	glRotated(counter,0.75,0.75,0.25);
	
	glLineWidth(4.0);
	
	glColor4f(0,0,0,1);
	glutWireCube(4.0f);
	
	glLoadIdentity();
	glDisable(GL_DEPTH_TEST);
	glTranslatef(0,0,-20);
	
	compositor->draw();
		
}

void Nidhoggr::selectionPaintGL (){
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	glLoadIdentity();
}


//OpenGL Functions
void Nidhoggr::initGL () {

	/* Contains all the initial values for a generic openGL scene setup:
		VSync:			enabled
		Texturing:		2D textures enabled
						Magnification filter-	linear
						Minification filter-	linear, mipmapped
						Border Color-			clear (0.0,0.0,0.0,0.0)
		Shading:		Smooth shading
		Clearing:		Clear color-			black
						Clear depth-			1.0
						Accum clear color-		black
						Stencil clear value-	0x0
		Depth Test:		Enabled
						Depth Function-			Less than or equal
		Blending:		Enabled
						Blending Function-		Source alpha, one minus source alpha
		Alpha Test:		Enabled
						Alpha Function-			Greater than 0.05
		Stencil Test:	Disabled
		Perspective:	Nicest
		Antialiasing:	Lines-					Enabled
						Points-					Enabled
		Lighting:		Enabled
						Light Model-			Separate Specular
						Material Settings-		Using glColor
						Light0-
							Ambient-			(0.2,0.2,0.2,1.0)
							Diffuse-			(0.6,0.6,0.6,1.0)
							Specular-			(0.35,0.35,0.35,1.0)
							Position-			At origin
						Specular Reflection-	Enabled, shininess- 20
	*/
	{					
							

		#if defined(__APPLE__) || defined(MACOSX)
		GLint VBL = 1;
		CGLSetParameter(CGLGetCurrentContext(),  kCGLCPSwapInterval, &VBL);
		#endif

		//===================================================================
			//Texturing
		//===================================================================
		glEnable(GL_TEXTURE_2D);

		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		GLfloat borderColor[4] = {0.0,0.0,0.0,0.0};
		glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,borderColor);
		//===================================================================
			//Shading
		//===================================================================
		glShadeModel(GL_SMOOTH);
		//===================================================================
			//Clearing
		//===================================================================
		glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		glClearAccum(0.0f, 0.0f, 0.0f, 0.0f);
		glClearDepth(1.0f);
		glClearStencil(0x0);
		//===================================================================
			//Depth testing
		//===================================================================
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LEQUAL);
		//===================================================================
			//Blending
		//===================================================================
		glEnable (GL_BLEND); 
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		//===================================================================
			//Alpha Testing
		//===================================================================
		glEnable(GL_ALPHA_TEST);
		glAlphaFunc(GL_GREATER, 0.05f);
		//===================================================================
			//Stencil Testing
		//===================================================================
		glDisable(GL_STENCIL_TEST);
		//===================================================================
			//Perspective
		//===================================================================
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
		//===================================================================
			//Antialiasing
		//===================================================================
		glEnable(GL_LINE_SMOOTH);
			glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
		glEnable(GL_POINT_SMOOTH);
			glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
		//===================================================================
			//Lighting
		//===================================================================	
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		
//		glLightModelf (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);

		//--------------------------------
			//Light Color
		GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
		GLfloat diffuseLight[] = { 0.6f, 0.6f, 0.6, 1.0f };
		GLfloat specularLight[] = { 0.35f, 0.35f, 0.35f, 1.0f };

		glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
		glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
		glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
		//--------------------------------
			//Light Position
		GLfloat position[] = { 0.0f, 0.0f, 0.0f, 1.0f };
		glLightfv(GL_LIGHT0, GL_POSITION, position);		
		//--------------------------------
			//Material settings
		glEnable(GL_COLOR_MATERIAL);
		glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);	
		//--------------------------------
			//Specular Reflection settings
		GLfloat specReflection[] = { 0.5f, 0.5f, 0.5f, 1.0f };
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specReflection);
		glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 20);
		
		openGLInitialized = true;

	}
}

void Nidhoggr::resizeGL (float w,float h){
	if ( h == 0 ){ h = 1; }
	
	pixelWidth = w;
	pixelHeight = h;
	
	glViewport(0,0,w,h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
		gluPerspective(45.0f,w/h,0.1,2000.0f);
	glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		
		
	
	GLdouble modelviewMatrix[16];
	GLdouble projectionMatrix[16];
	GLint		viewport[4];
	
	glGetDoublev(GL_MODELVIEW_MATRIX,modelviewMatrix);
	glGetDoublev(GL_PROJECTION_MATRIX,projectionMatrix);
	glGetIntegerv(GL_VIEWPORT,viewport);
	
	GLdouble bl_objX;	GLdouble tr_objX;
	GLdouble bl_objY; GLdouble tr_objY;
	GLdouble bl_objZ; GLdouble tr_objZ;
	
//	GLdouble winX = pixelWidth - 5;
//	GLdouble winY = pixelHeight - 5;
//	GLdouble winZ = 0;
	
	gluUnProject(1,1,0,modelviewMatrix,projectionMatrix,viewport,&bl_objX,&bl_objY,&bl_objZ);
	gluUnProject(w - 1,h - 1,0,modelviewMatrix,projectionMatrix,viewport,&tr_objX,&tr_objY,&tr_objZ);
	
	openGLWidth = tr_objX - bl_objX;
	openGLHeight = tr_objY - bl_objY;
	
	pvar( openGLWidth );
	pvar( openGLHeight );
	
	pvar( bl_objZ );
	
	glBindTexture(GL_TEXTURE_2D,0);
	glColor4f(0,0,0,1);
	glPointSize(5.0);
	glBegin(GL_POINTS);
		glVertex3f(objX,objY,objZ);
	glEnd();
}


void Nidhoggr::arg (int argc, char *argv[] ){
	for ( int i = 0; i < argc; ++i ){
		args.push_back( OString(argv[i]) );
	}
}





//General functions

Texture* Nidhoggr::loadTexture ( const OString& name, const OString& path,bool keep ){
	if ( textureStorage.find(name) != textureStorage.end() ){ return & textureStorage[name]; }
	Texture * tptr = NULL;
	
	if ( textureStorage_path_to_texture.find(path) == textureStorage_path_to_texture.end() ){
		textureStorage[name] = Texture(path,true,keep);
		tptr = & textureStorage[name];
		
		textureStorage_path_to_texture[ path ] = tptr;
		textureStorage_id_to_texture[ tptr->texID ] = tptr;
		textureStorage_id_to_name[ tptr->texID ] = name;
	}
	else{
		tptr = textureStorage_path_to_texture[path];
	}
	
	return tptr;
}

Texture* Nidhoggr::loadTextureForTextureBlock ( const OString& name, const OString& path ){
	if ( textureStorage.find(name) != textureStorage.end() ){ return & textureStorage[name]; }
	Texture * tptr = NULL;
	
	if ( textureStorage_path_to_texture.find(path) == textureStorage_path_to_texture.end() ){
		textureStorage[name] = Texture(path,false,true);
		tptr = & textureStorage[name];
		
		textureStorage_path_to_texture[ path ] = tptr;
		textureStorage_id_to_texture[ tptr->texID ] = tptr;
		textureStorage_id_to_name[ tptr->texID ] = name;
	}
	else{
		tptr = textureStorage_path_to_texture[path];
	}
	
	return tptr;	
}

Texture* Nidhoggr::getTexture ( const OString& name ){
	typeof( textureStorage.find(name) ) it = textureStorage.find(name);
	if ( it == textureStorage.end() ){ return emptyTexture; }
	return & ( it->second );
}

Texture* Nidhoggr::getTexture ( GLuint ID ){
	typeof( textureStorage_id_to_texture.find(ID) ) it = textureStorage_id_to_texture.find(ID);
	if ( it == textureStorage_id_to_texture.end() ){ return emptyTexture; }
	return it->second;
}

}

